<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>04.修改this指向</title>
    <!--1、引入react核心文件-->
    <script src="./js/react.development.js"></script>
    <!--2、引入react-dom核心文件-->
    <script src="./js/react-dom.development.js"></script>
    <!--3、引入babel转换文件-->
    <script src="./js/babel.min.js"></script>
</head>

<body>
    <!--4、创建容器-->
    <div id="root"></div>
    <!--5、设置脚本类型,相当于里面所有代码都默认处在严格模式下，而严格模式下的函数的this为undefined-->
    <script type="text/babel">
        //6、创建容器对象
        let root = ReactDOM.createRoot(document.querySelector('#root'));
        //7、创建类组件
        let { Component } = React;
        //案例：今天的心情好不好
        class App extends Component {
            //每一个类组件必须要有render方法，目的是为了渲染DOM结构
            //初始化状态数据
            state = {
                isGood: true
            }

            //修改this指向的办法：call、apply、bind
            //共同点：都是修改this指向的
            //不同点：call和apply之间不同在于传递的实际参数格式不同
            //函数.call(新的指向,实参1,实参2....)
            //函数.apply(新的指向,[实参1,实参2....])

            //不同点：call和bind之间不同在于是否修改完this指向立即执行
            //call修改完指向立即执行原函数
            //bind修改完指向不会立即执行原函数，而且还返回与原函数结构一模一样的新函数，只不过这个函数中的this是新的this指向


            //想要让事件函数中的this为组件实例化对象，办法有三种
            //1) 将事件函数从匿名函数结构转化成箭头函数


            //定义事件函数
            /* changeMood = function () {
                // this.setState({
                //     isGood: false
                // })
                console.log(this);
            } */

            //转化成箭头函数
            /* changeMood = () => {
                // this.setState({
                //     isGood: false
                // })
                console.log(this);
            } */

            constructor() {
                super();
                //修改指向
                console.log(this);
                // console.log(this.changeMood.bind(this)); //0x200
                this.changeMood = this.changeMood.bind(this);
            }


            //2) 在构造器中进行修改this指向(bind)
            changeMood = function (n) {
                //console.log(this);
                console.log(n);
                let { isGood } = this.state;
                this.setState({
                    isGood: !isGood
                })
            }

            //3) 在事件插值表达式中嵌入箭头函数进行包裹

            //总结：方法1和方法3之间的区别主要在于调用事件函数的时候是否需要传递实际参数，如果需要传递实际参数，则使用方法3，如果不需要则直接方法1


            //render的执行次数为1(初始化的时候)+n(当每一次state的值发生改变的时候)次
            render() {
                console.log('render...');
                //解构
                //查看组件实例化对象
                console.log(this);
                //this指向组件实例化对象
                //读取state状态数据
                let { isGood } = this.state;
                return <div>
                    <p>今天的心情:{isGood ? '好' : "不好"}</p>
                    {/* <button onClick={this.changeMood}>修改心情</button> */}
                    {/* 方法三 */}
                    <button onClick={() => { this.changeMood(10) }}>修改心情</button>
                </div >
            }
        }
        //8、渲染
        root.render(<App />); // let s1 = new App()
    </script>
</body>

</html>